/* $RCSFile: MultiSelectListDataType.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/UI/DataTypes/MultiSelectListDataType.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:29  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Globalization;

using AddonNice.Diagnostics;
using AddonNice.UI;
using AddonNice.UI.WebControls;
using AddonNice.Configuration;

namespace AddonNice.UI.DataTypes
{
	/// <summary>
	/// MultiSelectListDataType
	/// Implements a listbox that allows multiple selections 
	/// (returns a colon-delimited string)
	/// </summary>
	public class MultiSelectListDataType : BaseDataType
	{
		private string _dataValueField;
		private string _dataTextField;

		public MultiSelectListDataType(object _dataSource, string _textField, string _dataField)  
		{
			InnerDataType		= PropertiesDataType.List;
			InnerDataSource		= _dataSource;
			DataTextField		= _textField;
			DataValueField		= _dataField;
		}

		protected override void InitializeComponents()
		{
			ListBox lb                  =   new ListBox();
			lb.CssClass			        =   "NormalListBox";
			lb.SelectionMode	        =   ListSelectionMode.Multiple;
			lb.Width			        =   controlWidth;
            if ( HandleChanges )
            {
   		        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine("[V]MultiSelectListDataType InitializeComponents HandleChanges set",DataTypeTraceSwitch.Sw.Info);
                lb.AutoPostBack         =   true;
                lb.SelectedIndexChanged +=  new EventHandler(lb_SelectedIndexChanged); 
            }
			lb.DataSource		        =   DataSource;
			lb.DataValueField	        =   DataValueField;
			lb.DataTextField	        =   DataTextField;
            if ( ReadOnly )
                lb.Enabled              =   false;

			innerControl                =   lb;
            _IsInitialized              =   true;
		}

        void lb_SelectedIndexChanged(object sender, EventArgs e)
        {
    		if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType lb_SelectedIndexChanged sender: {0}",sender),DataTypeTraceSwitch.Sw.Info);
            string oldValue         =   Val;
            ReadDataFromEditControl();
            string newValue         =   Val;
            OnDataTypeEvent(new DataTypeEventArgs(DataTypeEventType.Changed,sender,e,oldValue,newValue));
        }
		        
		public override string DataValueField
		{
			get
			{
				return _dataValueField;
			}
			set
			{
				_dataValueField = value;
			}
		}

		public override string DataTextField
		{
			get
			{
				return _dataTextField;
			}
			set
			{
				_dataTextField = value;
			}
		}
        
		public override object DataSource
		{
			get
			{
				return InnerDataSource;
			}
			set
			{
				InnerDataSource = value;
			}
		}

   		public override void ResetDataSource(object newDataSrc,string SelVal)
		{
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType ResetDataSource : {0}, SelVal: {1}, (innerControl == null): {2}", newDataSrc,( SelVal == null )? string.Empty:SelVal,innerControl == null ),DataTypeTraceSwitch.Sw.Info);
			InnerDataSource = newDataSrc;
            Val             =   SelVal;
            if ( innerControl == null )
                return;
			ListBox lb = (ListBox) innerControl;
            if ( lb.Items.Count > 0 )
            {
                DataBind();
            }
		}

		public override string Val
		{
			get
			{
				return innerValue;
			}
			set
			{
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType Val Set value: {0},innerControl == null : {1}", value,innerControl == null ),DataTypeTraceSwitch.Sw.Info);
				innerValue = value; //Remove trailing ';'
                if ( innerControl == null )
                    return;
				//force to update value in control
   				Control c   =   null;
                if ( innerControl != null )
                    c   =   EditControl;
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType Val Control forced: {0}", c != null ),DataTypeTraceSwitch.Sw.Info);
			}
		}
		
        public override void DataBind()
        {
			try
			{
				ListBox lb			= (ListBox) innerControl;
                lb.DataSource       =   DataSource;
                lb.DataValueField   = DataValueField;
                lb.DataTextField    = DataTextField;
                lb.Items.Clear();
                lb.ClearSelection();
                lb.DataBind();
                //Provide a smart height depending on items number
                if (lb.Items.Count > 5)
                    lb.Rows = 5;
                if (lb.Items.Count > 10)
                    lb.Rows = 10;
                if (lb.Items.Count > 20)
                    lb.Rows = 15;
			    // some pb here, we are loosing the multi parameter ????, force it
                lb.SelectionMode	= ListSelectionMode.Multiple;
				// Store in string array
			    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType DataBind innerValue: {0}",innerValue),DataTypeTraceSwitch.Sw.Info);
				string[] vals		= innerValue.Split(new char[] {';'},StringSplitOptions.RemoveEmptyEntries);
	            if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType DataBind trying to select {0} items", vals.Length),DataTypeTraceSwitch.Sw.Info);
                int cnt =   0;
				foreach (string _val in vals)
				{
                    if (_val == string.Empty )
                        continue;
                    ListItem lst    =   lb.Items.FindByValue(_val);
                    if ( lst != null)
                    {
				        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType DataBind found and selecting: {0}", _val ),DataTypeTraceSwitch.Sw.Info);
                        lst.Selected = true;
                        cnt++;
                    }
				}
                if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType DataBind {0} items selected ", cnt),DataTypeTraceSwitch.Sw.Info);
                if ( cnt == 0 && vals.Length > 1 )
                {
                    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType DataBind not items selected on {0} values, resetting innervalue", vals.Length),DataTypeTraceSwitch.Sw.Info);
                    innerValue = string.Empty;
                }
			}
			catch (Exception ex)
			{
                if ( DataTypeTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]MultiSelectListDataType DataBind ex: {0}",ex),DataTypeTraceSwitch.Sw.Info);
                throw;
			}
        }

        /// <summary>
        /// Update value from control: used by eventhandler after a control change event triggered
        /// </summary>
        /// <returns></returns>
        public override string ReadDataFromEditControl()
		{
            Control Ctl =   EditControl;
            if (DataTypeTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType ReadDataFromEditControl BEG Control is null: {0}, Val: {1}.", (Ctl == null), Val ), DataTypeTraceSwitch.Sw.Info);
            if ( Ctl ==   null )
                return Val;
            if ( Ctl is ListBox)
            {
                ListBox lb          =   (ListBox)Ctl;
				StringBuilder sb    =   new StringBuilder();
				for (int i = 0; i < lb.Items.Count; i++)
				{
                    ListItem lst    =   lb.Items[i];
					if ( lst.Selected)
					{
						sb.AppendFormat("{0};",lst.Value);
			            if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType EditControl Set found selected: [{0}]  {1}/{2}", lst.Value,i,lb.Items.Count ),DataTypeTraceSwitch.Sw.Info);
					}
				}
				string result   = sb.ToString();
               // DO NOT use Value but use InnerValue
				innerValue      = result;
            }
            if (DataTypeTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType ReadDataFromEditControl END InnerValue: {0}.", innerValue), DataTypeTraceSwitch.Sw.Info);
            return Val;
        }

        public override Control EditControl
		{
			get
			{
				if (innerControl == null)
					InitializeComponents();
				return innerControl;
			}
			set
			{
                if (DataTypeTraceSwitch.Sw.TraceVerbose)
                {
                    bool dif = (innerControl != value);
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType EdiControl SET innerControl is dif new value: {0}", dif), DataTypeTraceSwitch.Sw.Info);
                }
                // here we receive the listbox from input, so we get the selected values
				if (value is ListBox)
				{
					ListBox lb = (ListBox)value;
					//Update value from control
			        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType EditControl Set lb SelectionMode: {0}, Count: {1}", lb.SelectionMode,lb.Items.Count),DataTypeTraceSwitch.Sw.Info);
					StringBuilder sb = new StringBuilder();
					for (int i = 0; i < lb.Items.Count; i++)
					{
                        ListItem lst    =   lb.Items[i];
						if ( lst.Selected)
						{
							sb.AppendFormat("{0};",lst.Value);
				            if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType EditControl Set found selected: [{0}]  {1}/{2}", lst.Value,i,lb.Items.Count ),DataTypeTraceSwitch.Sw.Info);
						}
					}
					string result   = sb.ToString();
                   // DO NOT use Value but use InnerValue
					innerValue      = result;
   	                innerControl    = lb;
				    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MultiSelectListDataType EditControl Set InnerValue: {0}", result ),DataTypeTraceSwitch.Sw.Info);
                    return;
				}
    			string ErrMsg   =  string.Format("MultiSelectListDataType EdiControl Set a Listbox values is required, a '{0} is given",value.GetType().Name);
    		    if ( DataTypeTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(ErrMsg,DataTypeTraceSwitch.Sw.Info);
    			throw new ArgumentException(ErrMsg);
			}
		}
	}
}